package com.pig.easy.bpm.mysql.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.pig.easy.bpm.mysql.reister.DynamicDataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * todo:
 *
 * @author : pig
 * @date : 2020/5/9 10:58
 */
@Slf4j
public class DynamicDataSourceConfiguration {

    @NacosInjected
    ConfigService configService;

    @Value("${spring.application.name}")
    private String dataId;

    @Bean
    @Primary
    @ConditionalOnMissingBean
    public DynamicDataSource dataSource() {

        System.out.println("#######DynamicDataSourceRegister DynamicDataSourceConfiguration = ");

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        DataSource defaultDataSource = null;
        // 根据注解开始创建数据源
        List<String> dataSourceList = DynamicDataSourceContextHolder.dataSourceIds;
        if (null == dataSourceList) {
            throw new RuntimeException("init datasource err , dataSourceList must not be null");
        }
        dataSourceList = dataSourceList.stream().distinct().collect(Collectors.toList());
        for (String dataSourceEnum : dataSourceList) {
            DataSource dataSource = createDataSource(dataSourceEnum);
            targetDataSources.put(dataSourceEnum, dataSource);
            if (null == defaultDataSource) {
                defaultDataSource = dataSource;
            }
        }
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);

        log.info("init dataSource success , init targetDataSources size:{}", targetDataSources.size());
        return dynamicDataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DynamicDataSource dynamicDataSource) {
        return new JdbcTemplate(dynamicDataSource);
    }


    public synchronized DruidDataSource createDataSource(String dataSource)  {

        System.out.println("#############createDataSource = " + dataSource);
        DruidDataSource datasource = new DruidDataSource();
        Map<String,String> configMap = new HashMap<>();
        try {
            //
            String getConfig = configService.getConfig(dataId+".properties","DEFAULT_GROUP",100l);
            for (String string : getConfig.split("[\\t\\n\\r]")) {
                if(string.contains("=") && string.split("=").length > 1){
                    configMap.put(string.split("=")[0].trim(),string.trim().split("=")[1].trim());
                } else if(string.contains(":") && string.split(":").length > 1){
                    configMap.put(string.split(":")[0].trim(),string.trim().split(":")[1].trim());
                }
            }
        } catch (NacosException e) {
            e.printStackTrace();
        }
        String url = configMap.getOrDefault("jdbc." + dataSource + ".url", null);
        String userName = configMap.getOrDefault("jdbc." + dataSource + ".username", null);
        String passWord = configMap.getOrDefault("jdbc." + dataSource + ".password", null);
        String driver = configMap.getOrDefault("jdbc." + dataSource + ".driver", null);

        if (null == url || null == userName || null == passWord || null == driver) {
            throw new RuntimeException("datasource init fail, config info is null, dataSource : " + dataSource);
        }
        
        log.info("createDataSource url:{} userName:{} passWord:{}", url, userName, passWord);
        datasource.setUrl("jdbc:mysql://" + url + "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false&allowMultiQueries=true&nullCatalogMeansCurrent=true" );
        datasource.setUsername(userName);
        datasource.setPassword(passWord);
        datasource.setDriverClassName(driver);
        datasource.setMaxActive(100);
        datasource.setInitialSize(5);
        datasource.setMinIdle(5);
        datasource.setMaxWait(30000);

        //间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
        datasource.setTimeBetweenConnectErrorMillis(60000);
        //一个连接在池中最小空闲的时间，单位是毫秒
        datasource.setMinEvictableIdleTimeMillis(300000);
        datasource.setValidationQuery("SELECT 'z'");
        datasource.setTestWhileIdle(true);
        datasource.setTestOnBorrow(false);
        datasource.setTestOnReturn(false);
        datasource.setPoolPreparedStatements(false);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(20);
        //超过时间限制是否回收
        datasource.setRemoveAbandoned(true);
        //超时时间；单位为秒。180秒=3分钟
        datasource.setRemoveAbandonedTimeout(180);
        //关闭abanded连接时输出错误日志
        datasource.setLogAbandoned(false);
        List<Filter> filters = new ArrayList<>();
        StatFilter statFilter = new StatFilter();
        statFilter.setMergeSql(true);
        statFilter.setLogSlowSql(true);
        statFilter.setSlowSqlMillis(3000);
        filters.add(statFilter);
        datasource.setProxyFilters(filters);
        try {
            datasource.init();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("druid datasource init fail");
        }
        return datasource;
    }

//    public synchronized DataSource createDataSource(String dataSource)  {
//
//        System.out.println("#############createDataSource = " + dataSource);
//        DruidXADataSource datasource = new DruidXADataSource();
//        Map<String,String> configMap = new HashMap<>();
//        try {
//            //
//            String getConfig = configService.getConfig(dataId+".properties","DEFAULT_GROUP",100l);
//            for (String string : getConfig.split("[\\t\\n\\r]")) {
//                if(string.contains("=") && string.split("=").length > 1){
//                    configMap.put(string.split("=")[0].trim(),string.trim().split("=")[1].trim());
//                } else if(string.contains(":") && string.split(":").length > 1){
//                    configMap.put(string.split(":")[0].trim(),string.trim().split(":")[1].trim());
//                }
//            }
//        } catch (NacosException e) {
//            e.printStackTrace();
//        }
//        String url = configMap.getOrDefault("jdbc." + dataSource + ".url", null);
//        String userName = configMap.getOrDefault("jdbc." + dataSource + ".username", null);
//        String passWord = configMap.getOrDefault("jdbc." + dataSource + ".password", null);
//        String driver = configMap.getOrDefault("jdbc." + dataSource + ".driver", null);
//
//        if (null == url || null == userName || null == passWord || null == driver) {
//            throw new RuntimeException("datasource init fail, config info is null, dataSource : " + dataSource);
//        }
//        log.info("createDataSource url:{} userName:{} passWord:{}", url, userName, passWord);
//        datasource.setUrl("jdbc:mysql://" + url + "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false" );
//        datasource.setUsername(userName);
//        datasource.setPassword(passWord);
//        datasource.setDriverClassName(driver);
//        datasource.setMaxActive(100);
//        datasource.setInitialSize(5);
//        datasource.setMinIdle(5);
//        datasource.setMaxWait(30000);
//
//        //间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
//        datasource.setTimeBetweenConnectErrorMillis(60000);
//        //一个连接在池中最小空闲的时间，单位是毫秒
//        datasource.setMinEvictableIdleTimeMillis(300000);
//        datasource.setValidationQuery("SELECT 'z'");
//        datasource.setTestWhileIdle(true);
//        datasource.setTestOnBorrow(false);
//        datasource.setTestOnReturn(false);
//        datasource.setPoolPreparedStatements(false);
//        datasource.setMaxPoolPreparedStatementPerConnectionSize(20);
//        //超过时间限制是否回收
//        datasource.setRemoveAbandoned(true);
//        //超时时间；单位为秒。180秒=3分钟
//        datasource.setRemoveAbandonedTimeout(180);
//        //关闭abanded连接时输出错误日志
//        datasource.setLogAbandoned(false);
//        List<Filter> filters = new ArrayList<>();
//        StatFilter statFilter = new StatFilter();
//        statFilter.setMergeSql(true);
//        statFilter.setLogSlowSql(true);
//        statFilter.setSlowSqlMillis(3000);
//        filters.add(statFilter);
//        datasource.setProxyFilters(filters);
//        try {
//            datasource.init();
//        } catch (SQLException e) {
//            e.printStackTrace();
//            throw new RuntimeException("druid datasource init fail");
//        }
//
//        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
//        xaDataSource.setXaDataSource(datasource);
//        xaDataSource.setUniqueResourceName(dataSource);
//        return xaDataSource;
//    }
}
